package sgc.manager;

import geral.manager.UtilManager;
import geral.util.FacesUtil;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.enterprise.context.SessionScoped;
import javax.faces.event.ValueChangeEvent;
import javax.inject.Inject;
import javax.inject.Named;

import org.primefaces.event.ScheduleEntryMoveEvent;
import org.primefaces.event.SelectEvent;
import org.primefaces.model.DefaultScheduleEvent;
import org.primefaces.model.LazyScheduleModel;
import org.primefaces.model.ScheduleEvent;

import seguranca.helper.SegurancaManagerHelper;
import br.com.sgc.entities.geral.Agendamento;
import br.com.sgc.entities.geral.Cliente;
import br.com.sgc.entities.geral.Paciente;
import br.com.sgc.entities.geral.PacienteAnimal;
import br.com.sgc.entities.geral.PacientePessoa;
import br.com.sgc.entities.geral.Sala;
import br.com.sgc.entities.geral.TipoProcedimento;
import br.com.sgc.entities.geral.Tratamento;
import br.com.sgc.entities.geral.TratamentoEstetico;
import br.com.sgc.entities.medico.Medico;
import br.com.sgc.entities.veterinaria.Animal;
import br.com.sgc.enuns.StatusAgendamento;
import br.com.sgc.session.AgendamentoSession;
import br.com.sgc.session.AnimalSession;
import br.com.sgc.session.ClienteSession;
import br.com.sgc.session.GenericSession;
import br.com.sgc.session.MedicoSession;
import br.com.sgc.session.PacienteAnimalSession;
import br.com.sgc.session.PacientePessoaSession;

@Named
@SessionScoped
public class AgendaManager implements Serializable{

	private static final long serialVersionUID = -5538226494078778906L;
	
	@Inject private UtilManager utilManager;
	
	@EJB private AgendamentoSession agendamentoSession;
	
	@EJB private GenericSession<Paciente> pacienteSession;
	
	@EJB private PacientePessoaSession pacientePessoaSession;
	
	@EJB private PacienteAnimalSession pacienteAnimalSession;
	
	@EJB private ClienteSession clienteSession;
	
	@EJB private GenericSession<Tratamento> tratamentoSession;
	
	@EJB private MedicoSession medicoSession;
	
	@EJB private AnimalSession animalSession;
	
	private static final String PACIENTE = "Paciente: ";
	
			
	
	private LazyScheduleModel lazyModel;  
	private ScheduleEvent event = new DefaultScheduleEvent();
	
	private List<Tratamento> tratamentos = new ArrayList<Tratamento>();
	private Tratamento tratamento = new Tratamento();
	
	private List<Sala> salas = new ArrayList<Sala>();
	private Sala sala = new Sala();
	
	private List<Paciente> pacientes = new ArrayList<Paciente>();
	private Paciente paciente = new Paciente();
	
	private List<Agendamento> agendamentos = new ArrayList<Agendamento>();
	private Agendamento agendamento = new Agendamento();
	
	private List<Medico> medicos = new ArrayList<Medico>();
	private Medico medico = new Medico();
	
	private Cliente cliente = new Cliente();
	private List<Cliente> clientes = new ArrayList<Cliente>();
	
	private Animal animal = new Animal();
	private List<Animal> animais = new ArrayList<Animal>();
	
	private TipoProcedimento tipoProcedimento = new TipoProcedimento();
	private List<TipoProcedimento> procedimentos = new ArrayList<TipoProcedimento>();
	
	
	public AgendaManager() {
		lazyScheduleModel();
	}

	private void lazyScheduleModel() {
		agendamento = new Agendamento();
		lazyModel = new LazyScheduleModel() {
			private static final long serialVersionUID = 1L;

			@Override
			 public void loadEvents(Date start, Date end) {
				agendamentos = agendamentoSession.findAgendamentosByDate(start, end, medico.getId(), utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
				for(Agendamento ag: agendamentos){
					agendamento = ag;
					createAgendamento();
				}
			 	agendamento = new Agendamento();
	
			 }
		};
		
		if(SegurancaManagerHelper.getSegurancaManager().getIsClinica()){
			agendamento.setPaciente(new PacientePessoa());
		} else {
			agendamento.setPaciente(new PacienteAnimal());
		}
		
	}
	
	public String exibirAgendaMedicos(){
		medicos = medicoSession.findAll(Medico.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
		return "listAgendaMedico";
	}
	
	public String exibirAgendaMedico(){
		utilManager.getMedicoManager().setMedico(medico);
		utilManager.getMedicoManager().showVisualizacaoMedico();
		if(SegurancaManagerHelper.getSegurancaManager().getIsClinica()){
			agendamento.setPaciente(new PacientePessoa());
		} else {
			agendamento.setPaciente(new PacienteAnimal());
		}
		return "homeSGC";
	}
	
	public String exibirTodasAgendas(){
		medico = new Medico();
		lazyScheduleModel();
		return "homeSGC";
	}

	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public void addEvent() {
		try {
			agendamento.setFuncionario(utilManager.getSegurancaManager().getFuncionarioLogado());
			agendamento.setStatusAgendamento(StatusAgendamento.AGENDADO);
			agendamento.setClinica(utilManager.getSegurancaManager().getUsuarioLogado().getClinica());
			agendamentoSession.save(agendamento);
			
	        if(event.getId() == null){
	        	createAgendamento();
	        } else {  
	            lazyModel.updateEvent(event);
	        }
		} catch (Exception e) {
			e.printStackTrace();
			FacesUtil.mensErro(e.getMessage());
		}
          
        event = new DefaultScheduleEvent();  
    }

	private void createAgendamento() {
		
		Calendar data = Calendar.getInstance();
		data.setTime(agendamento.getDataAgendamento());
		
		Calendar hora = Calendar.getInstance();
		hora.setTime(agendamento.getHoraAgendamento());
		
		Calendar cal = Calendar.getInstance();
		cal.set(data.get(Calendar.YEAR), data.get(Calendar.MONTH), data.get(Calendar.DATE), hora.get(Calendar.HOUR_OF_DAY), hora.get(Calendar.MINUTE));

		DefaultScheduleEvent ev = new DefaultScheduleEvent();
		
		
		ev.setStartDate(cal.getTime());
		ev.setAllDay(false);
		if(agendamento.getPaciente() != null && agendamento.getPaciente().getId() != null){
			agendamento.setPaciente(pacienteSession.findById(Paciente.class, agendamento.getPaciente().getId()));
		
			if(agendamento.getPaciente() instanceof PacienteAnimal){
				agendamento.setPaciente(pacienteAnimalSession.findById(PacienteAnimal.class, agendamento.getPaciente().getId(), true));
			} else if(agendamento.getPaciente() instanceof PacientePessoa){
				agendamento.setPaciente(pacientePessoaSession.findById(PacientePessoa.class, agendamento.getPaciente().getId(), true));
			}
			
		}
		
		String title = "";
		
		if(agendamento.getTipoProcedimento().getExibirMedicos()){
			agendamento.setMedico(medicoSession.findById(Medico.class, agendamento.getMedico().getId()));
			title = PACIENTE+agendamento.getPaciente().getDisplayNome() + " - "+agendamento.getStatusAgendamento().getDescricao()+": "+agendamento.getMedico().getNome();
			cal.add(Calendar.MINUTE, 20);
		} else if(agendamento.getTipoProcedimento().getExibirTratamentos()) {
			agendamento.setTratamento(tratamentoSession.findById(Tratamento.class, agendamento.getTratamento().getId()));
			title = PACIENTE+agendamento.getPaciente().getDisplayNome() + " - "+agendamento.getStatusAgendamento().getDescricao();
			cal.add(Calendar.MINUTE, ((TratamentoEstetico)agendamento.getTratamento()).getDuracaoTratamento());
		}

		ev.setTitle(title);
		ev.setEndDate(cal.getTime());
		
		
		ev.setStyleClass(agendamento.getId().toString());
		lazyModel.addEvent(ev);
	}  
      
	
    public void onEventSelect(SelectEvent selectEvent) {
    	event = (ScheduleEvent) selectEvent.getObject();
    	agendamento = agendamentoSession.findById(Agendamento.class, new Long(event.getStyleClass()), true);
        if(agendamento == null){
        	agendamento = new Agendamento();
        	if(SegurancaManagerHelper.getSegurancaManager().getIsClinica()){
    			agendamento.setPaciente(new PacientePessoa());
    		} else {
    			agendamento.setPaciente(new PacienteAnimal());
    		}
        } else {
        
	        agendamento.setPaciente(pacienteSession.findById(Paciente.class, agendamento.getPaciente().getId()));
	        	
	        
	        if(agendamento.getPaciente() instanceof PacienteAnimal){
	        	agendamento.setPaciente(pacienteAnimalSession.findById(PacienteAnimal.class, agendamento.getPaciente().getId(), true));
	        	cliente = animalSession.findById(Animal.class, ((PacienteAnimal)agendamento.getPaciente()).getAnimal().getId(), true).getDonoAnimal();
	        	animais = animalSession.findAllByCliente(cliente);
	        }
	        agendamento.setTipoProcedimento(utilManager.getTipoProcedimentoManager().getTipoProcedimentoSession().findById(TipoProcedimento.class, agendamento.getTipoProcedimento().getId()));
	        
        }
        
        agendamento.setClinica(utilManager.getSegurancaManager().getUsuarioLogado().getClinica());
        
        if(utilManager.getSegurancaManager().getIsClinica())
    		pacientes = pacienteSession.findAll(Paciente.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
    	else
    		clientes = clienteSession.findAll(Cliente.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId(), true);
    	
    	utilManager.getTipoProcedimentoManager().list();
    	procedimentos = utilManager.getTipoProcedimentoManager().getListTipoProcedimento();
    	
    	if(agendamento.getTipoProcedimento() != null && agendamento.getTipoProcedimento().getId() != null){
    	
    		if(agendamento.getTipoProcedimento().getExibirTratamentos()){
    			tratamentos = tratamentoSession.findAll(Tratamento.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
    			agendamento.setTratamento(tratamentoSession.findById(Tratamento.class, agendamento.getTratamento().getId()));
    		}
    	
    		if(agendamento.getTipoProcedimento().getExibirMedicos()){
    			medicos = medicoSession.findAll(Medico.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
    			agendamento.setMedico(medicoSession.findById(Medico.class, agendamento.getMedico().getId()));
    		}
    	}
    }  
      
    public void onDateSelect(SelectEvent selectEvent) {
    	Date data = (Date) selectEvent.getObject();
    	agendamento = new Agendamento();
    	if(SegurancaManagerHelper.getSegurancaManager().getIsClinica()){
			agendamento.setPaciente(new PacientePessoa());
			pacientes = pacienteSession.findAll(Paciente.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
		} else {
			agendamento.setPaciente(new PacienteAnimal());
			clientes = clienteSession.findAll(Cliente.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId(), true);
			cliente = new Cliente();
			animais = new ArrayList<Animal>();
		}
    	
    	agendamento.setDataAgendamento(data);
    	utilManager.getTipoProcedimentoManager().list();
    	procedimentos = utilManager.getTipoProcedimentoManager().getListTipoProcedimento();
        event = new DefaultScheduleEvent(Math.random() + "", data, data);  
    }  
    
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void onEventMove(ScheduleEntryMoveEvent event) {
    	agendamento = agendamentoSession.findById(Agendamento.class, new Long(event.getScheduleEvent().getStyleClass()), true);
    	
    	Calendar novaData = Calendar.getInstance();
    	novaData.setTime(agendamento.getDataAgendamento());
    	novaData.add(Calendar.DATE, event.getDayDelta());
    	agendamento.setDataAgendamento(novaData.getTime());
    	
    	Calendar novaHora = Calendar.getInstance();
    	novaHora.setTime(agendamento.getHoraAgendamento());
    	novaHora.add(Calendar.MINUTE, event.getMinuteDelta());
    	agendamento.setHoraAgendamento(novaHora.getTime());
    	
    	updateEvent();
    	
    }  
    
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void updateEvent() {
		try {
			agendamento.setFuncionario(utilManager.getSegurancaManager().getFuncionarioLogado());
			agendamento.setClinica(utilManager.getSegurancaManager().getUsuarioLogado().getClinica());
			agendamentoSession.update(agendamento);
        	createAgendamento();
        	
		} catch (Exception e) {
			e.printStackTrace();
			FacesUtil.mensErro(e.getMessage());
		}
          
        event = new DefaultScheduleEvent();  
    }

	public void showTipoConsulta(ValueChangeEvent event){
    	agendamento.setTipoProcedimento(utilManager.getTipoProcedimentoManager().getTipoProcedimentoSession().findById(TipoProcedimento.class, event.getNewValue()));
    	if(agendamento.getTipoProcedimento().getExibirMedicos()){
    		medicos = medicoSession.findAll(Medico.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
    	} 
    	
    	if(agendamento.getTipoProcedimento().getExibirTratamentos()){
    		tratamentos = tratamentoSession.findAll(Tratamento.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId(), false);
    	} 
    }
      
    public void clearObjects(){
    	tratamentos = new ArrayList<Tratamento>();
    	tratamento = new Tratamento();
    	pacientes = new ArrayList<Paciente>();
    	paciente = new Paciente();
    	agendamento = new Agendamento();
    	sala = new Sala();
    	event = new DefaultScheduleEvent();
    }
    
    public void findAnimalCliente(){
    	animais = animalSession.findAllByCliente(cliente);
    }
	
	public ScheduleEvent getEvent() {
		return event;
	}

	public void setEvent(ScheduleEvent event) {
		this.event = event;
	}

	public LazyScheduleModel getLazyModel() {
		return lazyModel;
	}

	public void setLazyModel(LazyScheduleModel lazyModel) {
		this.lazyModel = lazyModel;
	}

	public Agendamento getAgendamento() {
		return agendamento;
	}

	public void setAgendamento(Agendamento agendamento) {
		this.agendamento = agendamento;
	}

	public List<Tratamento> getTratamentos() {
		return tratamentos;
	}

	public void setTratamentos(List<Tratamento> tratamentos) {
		this.tratamentos = tratamentos;
	}

	public Tratamento getTratamento() {
		return tratamento;
	}

	public void setTratamento(Tratamento tratamento) {
		this.tratamento = tratamento;
	}

	public List<Sala> getSalas() {
		return salas;
	}

	public void setSalas(List<Sala> salas) {
		this.salas = salas;
	}

	public Sala getSala() {
		return sala;
	}

	public void setSala(Sala sala) {
		this.sala = sala;
	}

	public List<Paciente> getPacientes() {
		return pacientes;
	}

	public void setPacientes(List<Paciente> pacientes) {
		this.pacientes = pacientes;
	}

	public Paciente getPaciente() {
		return paciente;
	}

	public void setPaciente(Paciente paciente) {
		this.paciente = paciente;
	}

	public List<Agendamento> getAgendamentos() {
		return agendamentos;
	}

	public void setAgendamentos(List<Agendamento> agendamentos) {
		this.agendamentos = agendamentos;
	}

	public List<Medico> getMedicos() {
		return medicos;
	}

	public void setMedicos(List<Medico> medicos) {
		this.medicos = medicos;
	}

	public Medico getMedico() {
		return medico;
	}

	public void setMedico(Medico medico) {
		this.medico = medico;
	}

	public Cliente getCliente() {
		return cliente;
	}

	public void setCliente(Cliente cliente) {
		this.cliente = cliente;
	}

	public List<Cliente> getClientes() {
		return clientes;
	}

	public void setClientes(List<Cliente> clientes) {
		this.clientes = clientes;
	}

	public Animal getAnimal() {
		return animal;
	}

	public void setAnimal(Animal animal) {
		this.animal = animal;
	}

	public List<Animal> getAnimais() {
		return animais;
	}

	public void setAnimais(List<Animal> animais) {
		this.animais = animais;
	}

	public TipoProcedimento getTipoProcedimento() {
		return tipoProcedimento;
	}

	public void setTipoProcedimento(TipoProcedimento tipoProcedimento) {
		this.tipoProcedimento = tipoProcedimento;
	}

	public List<TipoProcedimento> getProcedimentos() {
		return procedimentos;
	}

	public void setProcedimentos(List<TipoProcedimento> procedimentos) {
		this.procedimentos = procedimentos;
	}
	
}